#include "Menu.h"
#include "OtherVSR.h" // RA C3

using namespace std;

struct ShowFindUpdateVSR { //VSR B3

    bool operator () (Product a, Product b) {
        return (a.get_prod_price() < b.get_prod_price());
    }

    static void show(Menu m) {
        // CALL BOOL OPERATOR FUNCTION HERE
        vector<Product> prods2 = m.get_prods(); //VSR B3
        cout << "List of all products sorted by price \n"; //VSR B3
        ShowFindUpdateVSR comp; //VSR B3
        sort(prods2.begin(), prods2.end(), comp); //VSR B3

        for (int i = 0; i < prods2.size(); ++i) { //VSR B3
            cout << prods2[i].get_prod_id() << " "
                    << prods2[i].get_cat_id() << " "
                    << prods2[i].get_prod_name() << " "
                    << prods2[i].get_prod_price() << " " << endl;
        }
    }

    static void find(Menu m) {
        double sum = 0;
        int c = 1;
        bool a = false;
        vector <Product> prods = m.get_prods();
        vector <Cart_item> cart_items = m.get_cart_items();
        vector <Category> cats = m.get_cats();
        Category selected_cat;


        while (c != '0') {
            cout << "Finds total sales for a given category \n"; //VSR B3
            cout << "Please select a category:" << endl;
            for (int i = 0; i < cats.size(); ++i) {
                cout << cats[i].get_cat_id() << " - " << cats[i].get_cat_name() << endl;
            }
            cout << "0 - Return to Main Menu" << endl << endl;
            cin >> c;

            int j;
            for (j = 0; j < cats.size(); j++) {
                if (cats[j].get_cat_id() == c) {
                    selected_cat = cats[j];
                    a = true;
                    break;
                }
            }

            if (c == 0) {
                break;
            }
            else if (a == false) {
                cout << "Sorry, that was not a valid choice. Please try again." << endl;
            }
            else {
                for (int i = 0; i < prods.size(); ++i)
                    if (prods[i].get_cat_id() == selected_cat.get_cat_id()) {
                        for (int j = 0; j < cart_items.size(); ++j) {
                            if (prods[i].get_prod_id() == cart_items[j].get_prod_id()) {
                                sum = sum + prods[i].get_prod_price() * cart_items[j].get_prod_qty();
                            }
                        }
                    }
            }
            cout << "Total sales for " << selected_cat.get_cat_name() << ": $" << sum << endl;
            sum = 0;
        }
    }


    //static void update(Menu m) {                              // RA C3
    static void update(vector<Cart_item> &cart_items) {         // RA C3
        int cart_item_id;
        int cart_id;
        int prod_id;
        int prod_qty;
        char c = 'c';

        //vector <Cart_item> cart_items = m.get_cart_items();   // RA C3


        cout << "Add new item to an existing cart\n"; //VSR B3
        cout << endl << endl;

        for (int i = 6000; i < 1000000; ++i) { //VSR B3
            while (c != 'q') {
                cout << "If you wish to stop adding items, enter 'q' for quit. If you'd like to continue, enter 'c'" << endl;
                cin >> c;
                cout << endl << endl;

                switch (c) {
                    case 'c':
                        cout << "Please enter your cart ID: ";
                        cin >> cart_id;
                        cout << endl << "Please enter the product ID of the product you wish to add: ";
                        cin >> prod_id;
                        cout << endl << "Please enter the product quantity: ";
                        cin >> prod_qty;
                        cart_item_id = i;

                        cart_items.push_back(Cart_item(cart_item_id, cart_id, prod_id, prod_qty));

                        // m.set_cart_items(cart_items);        // RA C3

                        cout << endl << "Your item has been added to your cart. Thank you." << endl;
                        break;

                    case 'q':
                        i = 1000000;
                        break;

                    default:
                        i = 1000000;
                        cout << "error. invalid choice. please try again.";
                }
            }
        }

    }
};

Menu::Menu() {
}

void Menu::display_main_menu() const {
    cout << "Here is the MAIN MENU \n";
    cout << "1. Display information." << endl;
    cout << "2. Read the data files." << endl;
    cout << "3. Show queries for data." << endl;
    cout << "4. Find queries for data." << endl;
    cout << "5. Update queries for data." << endl;
    cout << "6. Exit." << endl;
}

void Menu::display_info() const {
    cout << "Here is the Info requested \n";
    cout << "Project Part I, Vijay Rajvanshi, Rezan Achmad, Robertus Theodore \n";
}

void Menu::read() {
    cout << "Read file name then read store data \n";

    // Read the customer file, RA A1
    read_cust();

    // Read the cart file, VSR A2
    read_cart();

    // Read the category and product file, RT A3
    read_category_and_product();
}

/**
 * RA A1
 */
void Menu::read_cust() {
    // string cust_filename; // Customers data file name
    ifstream cust_file; // Customers data file reader
    int number_cust; // Number of Customers

    int cust_id; // Customer's ID
    string cust_name; // Customer's Name
    int addr_number; // Customer's Address number
    string addr_street; // Customer's Address Street
    int addr_postal_code; // Customer's Address Postal Code

    cout << "-- Read Customers Data --\n";

#ifdef DEBUG                            // RA C3
    cust_filename = "data/cust.dat";    // RA C3
#endif                                  // RA C3
    
#ifndef DEBUG                           // RA C3
    // Get customers data file name
    cout << "Input file name: ";
    cin >> cust_filename;
#endif                                  // RA C3

    // Read customers data
    cust_file.open(cust_filename.c_str());

    // Check file can be openned or not
    if (!cust_file.is_open()) {
        // cout << "File '" << cust_filename << "' can not be openned\n";
        throw InvalidFile();
    }

    // Clear vector of customers first
    custs.clear();

    // Read number of customers
    cust_file >> number_cust;

    // Iterate every line
    for (int i = 0; i < number_cust; ++i) {
        // Get one customer data
        cust_file >> cust_id >> cust_name >> addr_number >> addr_street >> addr_postal_code;

        // Check if success or not
        if (cust_file.fail()) {
            // Close file
            cust_file.close();

            // Throw invalid data exception
            throw InvalidData();
        }

        // Store customer data to Customer object
        Address cust_addr(addr_number, addr_street, addr_postal_code);
        Customer cust(cust_id, cust_name, cust_addr);

        // Add Customer object to Customer container
        custs.push_back(cust);
    }

    // Close file
    cust_file.close();
}

void Menu::read_cart() //VSR A2
{
    // string cart_filename; // Cart Item data file name
    ifstream cart_file; // Cart Item data file reader

    int year;
    int month;
    int day;

    int cart_id;
    int cust_id;
    int cart_item_id;
    int prod_id;
    int prod_qty;

    int size; //for first block of data
    int size1; //for second block of data

    cout << "-- Read Carts Data --\n";

#ifdef DEBUG                            // RA C3
    cart_filename = "data/carts.dat";   // RA C3
#endif                                  // RA C3
    
#ifndef DEBUG                           // RA C3
    // Get cart item data file name
    cout << "Input file name: ";
    cin >> cart_filename;
#endif                                  // RA C3

    // Read cart item data
    cart_file.open(cart_filename.c_str());

    // Check file can be opened or not
    if (!cart_file.is_open()) {
        throw InvalidFile();
    }
    
    // Clear vector of carts and cart items first
    carts.clear();              // RA C3
    cart_items.clear();         // RA C3

    cart_file >> size;
    for (int i = 0; i < size; ++i) {
        cart_file >> cart_id >> cust_id >> year >> month >> day;
        
        if(cart_file.fail()) {
            // Close file
            cart_file.close();

            // Throw invalid data exception
            throw InvalidData();
        }
        
        Date date(year, month, day);
        Cart cart_info(cart_id, cust_id, date);

        carts.push_back(cart_info);
    }

    cart_file >> size1;
    for (int i = 0; i < size1; ++i) {
        cart_file >> cart_item_id >> cart_id >> prod_id >> prod_qty;
        
        if(cart_file.fail()) {
            // Close file
            cart_file.close();

            // Throw invalid data exception
            throw InvalidData();
        }

        Cart_item cart_info(cart_item_id, cart_id, prod_id, prod_qty);

        cart_items.push_back(cart_info);
    }

    // Close file
    cart_file.close();
}

void Menu::read_category_and_product() {
    //Supporting variables
    // string catpro_filename, categ_name, prod_name;
    string categ_name, prod_name;
    int categ_count, prod_count;
    int cate_code;
    int categ_id, prod_id;
    double prod_price;

    cout << "-- Read Category & Product --\n";

#ifdef DEBUG                                    // RA C3
    catpro_filename = "data/catprd.dat";        // RA C3
#endif                                          // RA C3
    
#ifndef DEBUG                                   // RA C3
    // Get customers data file name
    cout << "Input file name: ";
    cin >> catpro_filename;
#endif                                          // RA C3

    //Initiation for file reading
    ifstream myfile(catpro_filename.c_str());

    //Process for reading the category and menu
    if (myfile.is_open()) {
        // Clear vector of category and product first
        cats.clear();   // RA C3
        prods.clear();  // RA C3
        
        myfile >> categ_count; // read the total category
        for (int i = 0; i < categ_count; i++) // iteration according to the amount of category listed
        {
            myfile >> categ_id; // read and insert the category id
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            myfile >> categ_name; // read and insert the category name
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            cats.push_back(Category(categ_id, categ_name)); // store the information to the category vector
        }

        myfile >> prod_count; // read the total product
        for (int i = 0; i < prod_count; i++) // iteration according to the amount of product listed
        {
            myfile >> prod_id; //read and insert the menu id
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            myfile >> categ_id; // read and insert the category id
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            myfile >> prod_name; // read and insert the product name
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            myfile >> prod_price; //read and insert the product price
            if (myfile.fail()) // check whether the code is error
            {
                myfile.clear();
                myfile.close();
                throw new InvalidData();
            }

            prods.push_back(Product(prod_id, categ_id, prod_name, prod_price)); // store the information to the vector
        }

        myfile.close(); // closing the file
    } else {
        throw InvalidFile();
    }
}

void Menu::show() const {
    int choose = -1;                                    // RA S2

    while (choose != 0) {
        cout << "-- Menu Show --" << endl;                      // RA S2
        cout << "1. Show All Categories" << endl;               // RA S2
        cout << "2. Show All Customers" << endl;                // RA S2
        cout << "3. Show All Products" << endl;                 // RA S2
        cout << "4. Show All Products in a Cart" << endl;       // RA C3
        cout << "0. Return to Main Menu" << endl;               // RA S2
        cout << "Choose Menu: ";                                // RA S2
        cin >> choose;                                          // RA S2

        switch (choose) {
            case 0:
                // Do nothing
                break;
            case 1:
                ShowFindUpdateRT::show(cats, prods);                    // RT S1
                break;
            case 2:
                ShowFindUpdateRA::show(custs);                          // RA S2
                break;
            case 3:
                ShowFindUpdateVSR::show(*this);                         // VSR S3
                break;
            case 4:                                                     // RA C3
                OtherVSR::cart_info(*this);                              // VSR C2
                break;                                                  // RA C3
            default:                                                    // RA S2
                cout << "Your input is incorrect. Try again." << endl;  // RA S2
                break;                                                  // RA S2
        }
    }
}

void Menu::find() const {
    int choose = -1;                                                    // RA S2
    
    while (choose != 0) {
        cout << "-- Menu Find --\n";
        cout << "1. Display total sales of a product" << endl;          // RA S2
        cout << "2. Calculate total sales of a customer" << endl;       // RA S2
        cout << "3. Calculate total sales of a category" << endl;       // RA S2
        cout << "0. Return to Main Menu" << endl;                       // RA S2
        cout << "Choose Menu: ";                                        // RA S2
        cin >> choose;                                                  // RA S2
    
        switch (choose) {                                               // RA S2
            case 0:                                                     // RA S2
                // Do nothing                                           // RA S2
                break;                                                  // RA S2
            case 1:
                ShowFindUpdateRT::find(cart_items, prods);              // RT S1
                break;
            case 2:
                ShowFindUpdateRA::find(carts, cart_items, prods, custs);// RA S2
                break;
            case 3:
                ShowFindUpdateVSR::find(*this);                         // VSR S3
                break;
            default:                                                    // RA S2
                cout << "Your input is incorrect. Try again." << endl;  // RA S2
                break;                                                  // RA S2
        }
    }
}

void Menu::update() {
    int choose = -1;                                                    // RA S2
    
    while (choose != 0) {                                               // RA S2
        cout << "-- Menu Find --\n";                                    // RA S2
        cout << "1. Add new category" << endl;                          // RA C3
        cout << "2. Add new product" << endl;                           // RA S2
        cout << "3. Delete product" << endl;                            // RA C3
        cout << "4. Change price of product" << endl;                   // RA C3
        cout << "5. Add new customer" << endl;                          // RA S2
        cout << "6. Add new cart" << endl;                              // RA C3
        cout << "7. Add new cart item" << endl;                         // RA S2
        cout << "8. Delete cart item" << endl;                          // RA C3
        cout << "0. Return to Main Menu" << endl;                       // RA S2
        cout << "Choose Menu: ";                                        // RA S2
        cin >> choose;                                                  // RA S2
    
        switch (choose) {                                               // RA S2
            case 0:                                                     // RA S2
                // Do nothing                                           // RA S2
                break;                                                  // RA S2
            case 1:                                                     // RA C3
                OtherRT::addNewCategory(cats);                          // RT C1
                break;                                                  // RA C3
            case 2:
                ShowFindUpdateRT::update(prods, cats);                  // RT S1
                break;
            case 3:                                                     // RA C3
                OtherRT::deleteProduct(prods);                          // RT C1
                break;                                                  // RA C3
            case 4:                                                     // RA C3
                OtherRT::changePrice(prods);                            // RT C1
                break;                                                  // RA C3
            case 5:
                ShowFindUpdateRA::update(custs);                        // RA S2
                break;
            case 6:                                                     // RA C3
                OtherVSR::add_new_cart(carts);                          // VSR C2
                break;                                                  // RA C3
            case 7:
                // ShowFindUpdateVSR::update(*this);                    // VSR S3
                ShowFindUpdateVSR::update(cart_items);                  // RA C3
                break;
            case 8:                                                     // RA C3
                OtherVSR::delete_cart_item(cart_items);                       // VSR C2
                break;                                                  // RA C3
            default:                                                    // RA S2
                cout << "Your input is incorrect. Try again." << endl;  // RA S2
                break;                                                  // RA S2
        }
    }
}
